/**
 * <p>文件名:	MemcacheManager.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 */
package com.caits.lbs.framework.services.memcache;

/**
 * <p>MemcacheManager</p>
 * <p>TODO</p>
 *
 * @author		周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 * @author 		宋晓达 ٩(·̮̃·̃)۶ (songxiaoda@ctfo.com)
 * @version		1.0.0
 * <table style="border:1px solid gray;">
 * <tr>
 * <th width="100px">版本号</th><th width="100px">动作</th><th width="100px">修改人</th><th width="100px">修改时间</th>
 * </tr>
 * <!-- 以 Table 方式书写修改历史 -->
 * <tr>
 * <td>0.0.0</td><td>创建类</td><td>zhb</td><td>2010-11-30 下午03:56:48</td>
 * </tr>
 * <tr>
 * <td>1.0.0</td><td>类改造, 可通过外部对服务器地址进行配置</td><td>sxd</td><td>2011-01-06 11:43</td>
 * </tr>
 * </table>
 */
import java.io.IOException;
import java.util.concurrent.TimeoutException;

import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
import net.rubyeye.xmemcached.utils.AddrUtil;

import org.apache.log4j.Logger;

import com.caits.lbs.exception.LBSException;
import com.caits.lbs.framework.log.CommonLogFactory;

/**
 * <p>
 * MemcacheManager
 * </p>
 * <p>
 * 所有需要调用memcache的地方都可以取得该类的实例，设置好serverAddress后就可以使用
 * </p>
 * 
 * @author 周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhb</td>
 *          <td>2011-3-18 下午05:16:27</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */
public class MemcacheManager implements IMemcacheService {

	/** 创建全局的唯一实例 */
	protected static MemcachedClient mcc = null;
	/** 高速缓存服务地址 */
	private String serverAddress = "";
	/** 网络超时时间阈值ms */
	private int soTimeout = 3 * 1000;
	/** 检测恢复连接的间隔：毫秒 */
	private long healSessionInterval = 5*1000;

	/**
	 * 字段 healSessionInterval 获取函数
	 * @return the healSessionInterval : long
	 */
	public long getHealSessionInterval() {
		return healSessionInterval;
	}

	/**
	 * 字段 healSessionInterval 设置函数 : long
	 * @param healSessionInterval the healSessionInterval to set
	 */
	public void setHealSessionInterval(long healSessionInterval) {
		this.healSessionInterval = healSessionInterval;
	}

	public String getServerAddress() {
		return serverAddress;
	}

	public void setServerAddress(String serverAddress) {
		this.serverAddress = serverAddress;
	}

	/** 日志记录 */
	protected static Logger log = CommonLogFactory.getLog();

	/** 采用单例模式 */
	protected static MemcacheManager memCachedManager = new MemcacheManager();

	/**
	 * 保护型构造方法，不允许实例化！
	 * 
	 */
	protected MemcacheManager() {
	}

	/**
	 * 初始化方法, 在applicationContext.xml 中 Memcache 内部服务中调用 , <bean
	 * id="memcacheServer" class="com.zjxl.lab.memcache.MemcacheManager"
	 * init-method="init"> <property name="serverAddress"
	 * value="10.1.99.115:11211"></property> </bean>
	 * */
	public void init() {
		/** 设置与缓存服务器的连接池 */
		MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddressMap(serverAddress));
		try {
			// 启用failure模式。希望网络恢复时自动恢复
			builder.setFailureMode(true);
			builder.setSessionLocator(new KetamaMemcachedSessionLocator());
			builder.setConnectTimeout(soTimeout);
			builder.setOpTimeout(soTimeout);
			builder.setConnectionPoolSize(3);
			builder.setHealSessionInterval(healSessionInterval);
			builder.setEnableHealSession(true);
			mcc = builder.build();
			log.info("Memcache initialization successful!" + serverAddress);
		} catch (IOException e) {
			log.error("初始化memcache连接失败:" + e.getLocalizedMessage(), e);
		}
	}

	/**
	 * 添加
	 * */
	public boolean add(String key, int exp, Object value) throws TimeoutException, InterruptedException, MemcachedException {
		return mcc.add(key, exp, value);
	}

	public boolean add(String key, int exp, Object value, long timeout) throws TimeoutException, InterruptedException, MemcachedException {
		return mcc.add(key, exp, value, timeout);
	}

	/**
	 * 替换
	 * */
	public boolean replace(String key, int exp, Object value) throws TimeoutException, InterruptedException, MemcachedException {
		return mcc.replace(key, exp, value);
	}

	/**
	 * FIXME 
	 * @param key
	 * @param exp
	 * @param value
	 * @param timeout
	 * @return
	 * @throws TimeoutException
	 * @throws InterruptedException
	 * @throws MemcachedException
	 */
	public boolean replace(String key, int exp, Object value, long timeout) throws TimeoutException, InterruptedException, MemcachedException {
		return mcc.replace(key, exp, value, timeout);
	}

	/* (non-Javadoc)
	 * @see com.caits.lbs.framework.services.memcache.IMemcacheService#put(java.lang.String, int, java.lang.Object)
	 */
	public boolean put(String key, int exp, Object value) throws LBSException {
		return put(key, exp, value, soTimeout);

	}

	public boolean put(String key, int exp, Object value, long timeout) throws LBSException {
		try {
			return mcc.set(key, exp, value, timeout);
		} catch (TimeoutException e) {
			String message = "设置缓存超时";
			log.error(message + e.getLocalizedMessage(), e);
			throw new LBSException(message, e);
		} catch (InterruptedException e) {
			String message = "设置缓存被打断";
			log.error(message + e.getLocalizedMessage(), e);
			throw new LBSException(message, e);
		} catch (MemcachedException e) {
			String message = "设置缓存异常";
			log.error(message + e.getLocalizedMessage(), e);
			throw new LBSException(message, e);
		} catch (Exception e) {
			String message = "设置缓存异常," + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		}

	}

	/**
	 * 根据指定的关键字获取对象. 内部测试方法, 准备删除.
	 * 
	 * @param key
	 * @return
	 * @throws MemcachedException
	 * @throws InterruptedException
	 * @throws TimeoutException
	 */
	public Object get(String key) throws LBSException {
		try {
			return mcc.get(key);
		} catch (TimeoutException e) {
			String message = "设置缓存超时" + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		} catch (InterruptedException e) {
			String message = "设置缓存被打断" + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		} catch (MemcachedException e) {
			String message = "设置缓存异常," + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		} catch (Exception e) {
			String message = "设置缓存异常," + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		}

	}

	@Override
	public boolean put(byte[] key, int exp, byte[] value, long expiry) throws LBSException {
		try {
			return mcc.set(new String(key), exp, value, expiry);
		} catch (TimeoutException e) {
			String message = "设置缓存超时";
			log.error(message + e.getLocalizedMessage(), e);
			throw new LBSException(message, e);
		} catch (InterruptedException e) {
			String message = "设置缓存被打断";
			log.error(message + e.getLocalizedMessage(), e);
			throw new LBSException(message, e);
		} catch (MemcachedException e) {
			String message = "设置缓存异常";
			log.error(message + e.getLocalizedMessage(), e);
			throw new LBSException(message, e);
		} catch (Exception e) {
			String message = "设置缓存异常," + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		}

	}

	@Override
	public byte[] get(byte[] key) throws LBSException {
		try {
			return mcc.get(new String(key));
		} catch (TimeoutException e) {
			String message = "设置缓存超时" + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		} catch (InterruptedException e) {
			String message = "设置缓存被打断" + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		} catch (MemcachedException e) {
			String message = "设置缓存异常," + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		} catch (Exception e) {
			String message = "设置缓存异常," + e.getLocalizedMessage();
			log.error(message, e);
			throw new LBSException(message, e);
		}
	}

	/**
	 * 获取变量<code>soTimeout</code>的值
	 * 
	 * @return 返回的数据类型是<code>int</code>
	 */
	public int getSoTimeout() {
		return soTimeout;
	}

	/**
	 * 设置变量<code> soTimeout</code> 的值
	 * 
	 * @param soTimeout
	 *            <code>soTimeout</code> 参数类型是<code>int</code>
	 */
	public void setSoTimeout(int soTimeout) {
		this.soTimeout = soTimeout;
	}

	/**
	 * 获取唯一实例.
	 * 
	 * @return
	 */
	public static MemcacheManager getInstance() {
		return memCachedManager;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.caits.lbs.framework.services.memcache.IMemcacheService#sendMessage
	 * (java.lang.String, java.lang.String)
	 */
	@Override
	public void sendMessage(String head, String body) {
		log.warn("memcache中未实现消息发送.");
	}

	/**
	 * 添加一个指定的值到缓存中.
	 * 
	 * @param key
	 * @param value
	 * @return
	 * @throws MemcachedException
	 * @throws InterruptedException
	 * @throws TimeoutException
	 */

	public static void main(String[] args) {
		IMemcacheService cache = MemcacheManager.getInstance();
		boolean ret = false;
		try {
			ret = cache.put("hello", 0, 234);
			ret = cache.put("kane", 0, "宋晓达");
			System.out.println("ret=cache.set(\"hello\", 0, 234);");
		} catch (LBSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("set value ret= " + ret);
		try {
			System.out.println("get value : " + cache.get("hello"));
			System.out.println("get value : " + cache.get("kane"));
		} catch (LBSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.exit(0);
	}
}
